
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Collections;

namespace ChEngine
{
    public partial class BitBoardDriver
    {
        const ulong m1 = 0x5555555555555555UL; //binary: 0101...
        const ulong m2 = 0x3333333333333333UL; //binary: 00110011..
        const ulong m4 = 0x0f0f0f0f0f0f0f0fUL; //binary:  4 zeros,  4 ones ...
        const ulong h01 = 0x0101010101010101UL; //the sum of 256 to the power of 0,1,2,3...
        public static int HowMany(ulong l)
        {

            //hamming weight
            l -= (l >> 1) & m1;             //put count of each 2 bits into those 2 bits
            l = (l & m2) + ((l >> 2) & m2); //put count of each 4 bits into those 4 bits 
            l = (l + (l >> 4)) & m4;        //put count of each 8 bits into those 8 bits 
            return (int)( (l * h01) >> 56);  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 
           
        }
        public static ulong CellToBit(int cell)
        {
            return 1UL << cell;
        }

        static int[] index64 = new int[64]{

           63,  0, 58,  1, 59, 47, 53,  2,

           60, 39, 48, 27, 54, 33, 42,  3,

           61, 51, 37, 40, 49, 18, 28, 20,

           55, 30, 34, 11, 43, 14, 22,  4,

           62, 57, 46, 52, 38, 26, 32, 41,

           50, 36, 17, 19, 29, 10, 13, 21,

           56, 45, 25, 31, 35, 16,  9, 12,

           44, 24, 15,  8, 23,  7,  6,  5

        };


        public unsafe static int BitToCell(ulong bit)
        {
            return index64[(((bit & (ulong)(-(long)bit)) * 0x07EDD5E59A4E28C2UL)) >> 58];
        }
        
        static Regex algebric = new Regex("(?'start'[abcdefgh][12345678])[-]*(?'dest'[abcdefgh][12345678])(?'flag'[:x#+qnrb]*)", RegexOptions.Compiled| RegexOptions.IgnoreCase);
        public static Movement ParseNotation(string s,BitBoardDriver b,Side side)
        {
            
            Match m = algebric.Match(s);
            if (m.Success)
            {
                Movement move = new Movement(
                                        ToCell(m.Groups["start"].Value)
                                        , ToCell(m.Groups["dest"].Value)
                                        ,ToFlag(m.Groups["flag"].Value));
                return move;
            }
            else
            {
                PGNParser pgn = new PGNParser(b);
                Movement move = pgn.ParseSingleMove(s,side);
                return move;
            }
        }

        private static MoveFlag ToFlag(string p)
        {
            MoveFlag f = MoveFlag.Nothing;
            if (!string.IsNullOrEmpty(p))
            {
                foreach (char c in p.ToLower())
                {
                    switch (c)
                    {
                        case '+':
                            f |= MoveFlag.Check;
                            break;
                        case '#':
                            f |= MoveFlag.Mate;
                            break;
                        case 'x':
                        case ':':
                            f |= MoveFlag.Capture;
                            break;
                        case 'q':
                        
                            f |= MoveFlag.PromoteToQueen;
                            break;
                        case 'r':

                            f |= MoveFlag.PromoteToRook;
                            break;
                        case 'n':

                            f |= MoveFlag.PromoteToKnight;
                            break;
                        case 'b':

                            f |= MoveFlag.PromoteToBishop;
                            break;


                    }
                }
            }
            else
                return MoveFlag.Nothing;
            return f;
        }
        static private ulong[] masks = new ulong[]
        {
            0x00000000FFFFFFFFUL,
            0x000000000000FFFFUL,
            0x00000000000000FFUL,
            0x000000000000000FUL,
            0x0000000000000003UL,
            1
        };
        static private void Bindex(ICollection<int> ires, int depth, ulong number,int pos,int mindex)
        {
            if (number == 0)
                return;
            if (depth == 1)
            {
                if (number != 0)
                {
                    ires.Add(pos);
                }
                return;
            }
            else
            {
                int half = depth / 2;
                Bindex(ires, half, number >> half, pos+half,mindex+1);
                Bindex(ires, half, number & masks[mindex], pos,mindex+1);
            }
        }
        public static ICollection<int> Unpack(ulong bits)
        {
            IList<int> x = new List<int>();
            while (bits != 0)
            {
                int z = BitToCell(bits & (~bits + 1));
                bits &= (0XFFFFFFFFFFFFFFFUL << z + 1);
                x.Add(z);
            }
            return x;
        }
        public static unsafe int Unpack(ulong bits,int* target)
        {
            int i=0;
            while (bits != 0)
            {
                int z = BitToCell(bits & (~bits + 1));
                bits &= (0XFFFFFFFFFFFFFFFUL << z + 1);
                *target = z;
                target++;
                i++;
            }
            return i;
        }
        public static int ToCell(string p)
        {
            string cols = "abcdefgh";
            string tokens = p.ToLower().Trim();
            int col = cols.IndexOf(tokens[0]);
            int row = int.Parse(new string(tokens[1],1));
            return (8 - row) * 8+col;
        }
        public bool InCheck( Side side,ulong bit)
        {
            int cell = BitToCell(bit);
            return moveGenerator.InCheck(Board, new int[] { cell }, side);
        }
        BitMove lastMoveWhite = new BitMove();
        public BitMove LasMoveWhite
        {
            get { return lastMoveWhite; }
            set { lastMoveWhite = value; }
        }
        BitMove lastMoveBlack = new BitMove();
        public BitMove LasMoveBlack
        {
            get { return lastMoveBlack; }
            set { lastMoveBlack = value; }
        }
        static int[] centerDist = new int[]{
                    565,
                    490,
                    425,
                    376,
                    350,
                    352,
                    381,
                    433,
                    500,
                    415,
                    340,
                    281,
                    250,
                    258,
                    301,
                    367,
                    447,
                    354,
                    265,
                    191,
                    150,
                    170,
                    235,
                    320,
                    412,
                    312,
                    213,
                    118,
                    0,
                    106,
                    201,
                    300,
                    400,
                    300,
                    201,
                    106,
                    0,
                    117,
                    213,
                    312,
                    412,
                    320,
                    235,
                    169,
                    150,
                    190,
                    265,
                    353,
                    447,
                    367,
                    301,
                    257,
                    250,
                    280,
                    340,
                    415,
                    500,
                    432,
                    381,
                    351,
                    350,
                    375,
                    425,
                    489
        };
        /// <summary>
        /// Returns the distance from a cell to the center in 1/100 of cell 
        /// Approximate value range from 0 - 500
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static int DistanceFromCenter(int cell)
        {
            return centerDist[cell];
        }
        public  bool InCheck(Side side)
        {
            return moveGenerator.InCheck(Board, side);
        }
    }
}